package com.info33.platform.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.info33.platform.business.app.vo.AppCenterVO;
import com.info33.platform.common.constant.AppConstant;
import com.info33.platform.common.constant.TableConstant;
import com.info33.platform.common.enums.LoginType;
import com.info33.platform.common.exception.ResultException;
import com.info33.platform.common.exception.TransactionalException;
import com.info33.platform.common.mvc.vo.Result;
import com.info33.platform.common.util.PasswordUtil;
import com.info33.platform.common.util.RedisUtils;
import com.info33.platform.system.dao.*;
import com.info33.platform.system.dto.SysTenantUserDTO;
import com.info33.platform.system.dto.SysUserDTO;
import com.info33.platform.system.entity.*;
import com.info33.platform.system.service.SysDeptPostService;
import com.info33.platform.system.service.SysUserProfileService;
import com.info33.platform.system.service.SysUserService;
import com.info33.platform.system.util.enums.UserTypeEnum;
import com.info33.platform.system.vo.SysUserDetailVO;
import com.info33.platform.system.vo.SysUserPerfect;
import com.info33.platform.system.vo.SysUserVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;

/**
 * @author admin
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUser> implements SysUserService {

    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private SysDeptDao sysDeptDao;
    @Autowired
    private SysTenantUserDao sysTenantUserDao;
    @Autowired
    private SysPostDao sysPostDao;
    @Autowired
    private SysDeptPostService sysDeptPostService;
    @Autowired
    private SysDeptPostDao sysDeptPostDao;
    @Autowired
    private SysUserProfileDao sysUserProfileDao;
    @Autowired
    private SysUserProfileService sysUserProfileService;

    @Override
    public Result<Object> pcResetPassWord(SysTenantUserDTO dto) {
        SysTenantUser entity = sysTenantUserDao.selectById(dto.getId());
        if (ObjectUtils.isEmpty(entity)) {
            return Result.error("该用户不存在");
        }
        Map<String, String> map = PasswordUtil.passwordMd5(AppConstant.DEFAULT_PASSWORD);
        return this.update(new UpdateWrapper<SysUser>()
                .set("password", map.get("password"))
                .set("salt", map.get("salt"))
                .eq(TableConstant.ID, entity.getUserId())) ? Result.ok() : Result.error();
    }

    @Override
    public Result<Object> pcChangePassword(SysUserDTO dto, SysUserVO currentUser) {
        SysUser old = sysUserDao.selectById(currentUser.getId());
        if (!old.getPassword().equals(PasswordUtil.confirmPass(dto.getOldPassWord(), old.getSalt()).get("password"))) {
            return Result.error("原密码错误");
        }
        Map<String, String> map = PasswordUtil.passwordMd5(dto.getPassword());
        return this.update(new UpdateWrapper<SysUser>()
                .set("password", map.get("password"))
                .set("salt", map.get("salt"))
                .eq(TableConstant.ID, currentUser.getId())) ? Result.ok() : Result.error();
    }

    /**
     * 递归获取部门 id 集合
     *
     * @param sysDeptVOList-
     * @param pid-
     * @return -
     */
    public void deptTreeToIdList(List<SysDept> sysDeptVOList, Long pid, List<Long> idList) {
        List<SysDept> collect = sysDeptVOList.stream().filter(l -> l.getPid().equals(pid)).collect(Collectors.toList());
        idList.addAll(collect.stream().map(SysDept::getId).collect(Collectors.toList()));
        collect.forEach(l -> deptTreeToIdList(sysDeptVOList, l.getId(), idList));
    }

    @Override
    public Page<SysUserVO> getUserListByDeptId(Page<SysUser> page, SysUserDTO dto, SysUserVO currentUser) {
        List<Long> idList = new ArrayList<>();
        idList.add(dto.getDeptDTO().getId());
        deptTreeToIdList(
                sysDeptDao.selectList(new QueryWrapper<SysDept>()
                        .eq(TableConstant.TENANT_ID, currentUser.getSysTenantUserVO().getTenantId())),
                dto.getDeptDTO().getId(),
                idList);
        return sysUserDao.getUserListByDeptId(page, dto, idList, currentUser);
    }

    @Override
    public Page<SysUserDetailVO> getAllUser(Page<SysUser> page, SysUserDTO dto, Long tenantId) {
        return sysUserDao.getAllUser(page, dto, tenantId);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class, Error.class})
    public Result<?> saveUser(SysUserDTO sysUserDTO, Long tenantId) {
        // 校验只能有一个主要部门
        List<SysDeptPost> sysDeptPostList = sysUserDTO.getSysDeptPostList();
        List<SysDeptPost> newList = sysDeptPostList.stream().filter(sysDeptPost -> Boolean.TRUE.equals(sysDeptPost.getPrincipal()))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(newList) || newList.size() > 1) {
            return Result.error("需给用户指定一个主要部门，且只能有一个");
        }
        //根据手机号查找，如果不存在则进行新增用户sys_user
        SysUser sysUser = sysUserDao.selectOne(new QueryWrapper<SysUser>().eq("mobile", sysUserDTO.getMobile()));
        if (ObjectUtils.isEmpty(sysUser)) {
            //添加用户信息
            sysUser = sysUserDao.getByTenantIdAndLoginName(tenantId, sysUserDTO.getLoginName());
            if (!ObjectUtils.isEmpty(sysUser)) {
                return Result.error("登录名已存在");
            }
            sysUser = new SysUser();
            Map<String, String> map = PasswordUtil.passwordMd5(AppConstant.DEFAULT_PASSWORD);
            sysUserDTO.setPassword(map.get("password"));
            sysUserDTO.setSalt(map.get("salt"));
            BeanUtils.copyProperties(sysUserDTO, sysUser);
            if (!save(sysUser)) {
                return Result.error("新增失败");
            }
            // 保存用户拓展信息
            SysUserProfile userProfile = new SysUserProfile();
            userProfile.setUserId(sysUser.getId());
            userProfile.setTrueName(sysUserDTO.getTrueName());
            userProfile.setNickName(userProfile.getTrueName());
            if (!sysUserProfileService.save(userProfile)) {
                throw new TransactionalException();
            }
        }
        // 添加租户-用户信息 sys_tenant_user
        if (!ObjectUtils.isEmpty(sysTenantUserDao.selectOne(new QueryWrapper<SysTenantUser>()
                .eq(TableConstant.TENANT_ID, tenantId)
                .eq("user_id", sysUser.getId())))) {
            return Result.error("此用户已存在");
        }
        SysTenantUser sysTenantUser = new SysTenantUser();
        sysTenantUser.setUserId(sysUser.getId());
        sysTenantUser.setStatus(sysUser.getStatus());
        sysTenantUser.setLocked(sysUserDTO.getTenantUserDTO().getLocked());
        //如果分配角色包含“管理员”角色 userType类型为ADMIN，否则为USER
        boolean flag = true;
        for (SysDeptPost sysDeptPost : sysDeptPostList) {
            SysPost sysPost = sysPostDao.selectById(sysDeptPost.getPostId());
            if (TableConstant.NEW_TENANT_INDEX.equals(sysPost.getIndexes())) {
                sysTenantUser.setUserType(UserTypeEnum.ADMIN);
                flag = false;
                break;
            }
        }
        if (flag) {
            sysTenantUser.setUserType(UserTypeEnum.USER);
        }
        if (sysTenantUserDao.insert(sysTenantUser) == 1) {
            //添加部门岗位
            for (SysDeptPost sysDeptPost : sysDeptPostList) {
                sysDeptPost.setUserId(sysTenantUser.getId());
            }
            if (Boolean.FALSE.equals(sysDeptPostService.saveBatch(sysDeptPostList))) {
                throw new TransactionalException("新增失败");
            }
            return Result.ok();
        }
        throw new TransactionalException("新增失败");
    }

    @Override
    @Transactional(rollbackFor = {Exception.class, Error.class})
    public Result<?> editUser(SysUserDTO sysUserDTO, Long tenantId) {
        // 校验只能有一个主要部门
        List<SysDeptPost> sysDeptPostList = sysUserDTO.getSysDeptPostList();
        if (sysDeptPostList.stream().filter(sysDeptPost -> Boolean.TRUE.equals(sysDeptPost.getPrincipal())).count() != 1L) {
            return Result.error("需给用户指定一个主要部门，且只能有一个");
        }
        if (sysDeptPostList.stream().map(l -> l.getDeptId() + TableConstant.COMMA + l.getPostId()).distinct().count() != Long.parseLong(sysDeptPostList.size() + "")) {
            return Result.error("存在重复部门与岗位");
        }
        SysTenantUser sysTenantUser = sysTenantUserDao.selectById(sysUserDTO.getId());
        if (ObjectUtils.isEmpty(sysTenantUser)) {
            return Result.error("数据不存在");
        }
        //校验手机号码是否存在
        if (!ObjectUtils.isEmpty(getOne(new QueryWrapper<SysUser>()
                .eq("mobile", sysUserDTO.getMobile())
                .ne(TableConstant.ID, sysTenantUser.getUserId())))) {
            return Result.error("手机号已存在");
        }
        SysUser sysUser = sysUserDao.selectById(sysTenantUser.getUserId());
        Integer version = sysUser.getVersion();
        BeanUtils.copyProperties(sysUserDTO, sysUser);
        sysUser.setId(sysTenantUser.getUserId());
        sysUser.setVersion(version);
        if (sysUserDao.updateById(sysUser) == 1) {
            sysDeptPostDao.delete(new QueryWrapper<SysDeptPost>().eq("user_id", sysTenantUser.getId()));
            //如果分配角色包含“管理员”角色 userType类型为ADMIN，否则为USER
            Boolean flag = true;
            for (SysDeptPost sysDeptPost : sysDeptPostList) {
                SysPost sysPost = sysPostDao.selectById(sysDeptPost.getPostId());
                if (TableConstant.NEW_TENANT_INDEX.equals(sysPost.getIndexes())) {
                    sysTenantUser.setUserType(UserTypeEnum.ADMIN);
                    flag = false;
                    break;
                }
            }
            if (flag) {
                sysTenantUser.setUserType(UserTypeEnum.USER);
            }
            sysTenantUser.setLocked(sysUserDTO.getTenantUserDTO().getLocked());
            // 修改用户拓展信息
            if (sysUserProfileDao.update(null, new LambdaUpdateWrapper<SysUserProfile>()
                    .set(SysUserProfile::getTrueName, sysUser.getTrueName())
                    .eq(SysUserProfile::getUserId, sysUser.getId())) != 1) {
                throw new TransactionalException();
            }
            if (sysTenantUserDao.updateById(sysTenantUser) == 1) {
                //添加部门岗位
                for (SysDeptPost sysDeptPost : sysDeptPostList) {
                    sysDeptPost.setUserId(sysTenantUser.getId());
                }
                return sysDeptPostService.saveBatch(sysDeptPostList) ? Result.ok() : Result.error();
            }
        }
        return Result.error("编辑失败");
    }

    @Override
    public SysUserDetailVO getUserDetail(Long id) {
        return sysUserDao.getUserDetail(id);
    }

    @Override
    public SysUserVO pcBaseInfo(SysUserVO sysCurrentUser) {
        return sysUserDao.pcBaseInfo(sysCurrentUser);
    }

    @Override
    public Page<SysUserVO> specificUserList(Page<SysUser> page, SysUserDTO dto, SysUserVO sysCurrentUser) {
        List<Long> idList = new ArrayList<>();
        idList.add(dto.getDeptDTO().getId());
        deptTreeToIdList(
                sysDeptDao.selectList(new QueryWrapper<SysDept>()
                        .eq(TableConstant.TENANT_ID, sysCurrentUser.getSysTenantUserVO().getTenantId())),
                dto.getDeptDTO().getId(),
                idList);
        return sysUserDao.specificUserList(page, dto, idList, sysCurrentUser);
    }

    @Override
    public SysUserVO pcDetail(SysUserVO sysCurrentUser) {
        return sysUserDao.pcDetail(sysCurrentUser);
    }

    @Override
    public List<String> queryUserSameLevelDeptAndParent(Long userId, Long tenantId) {
        List<String> resultList = new ArrayList<>();
        //查询当前用户部门id,parentId和部门名称
        Map<String, Object> map = sysUserDao.queryUserSameLevelDeptAndParent(userId, tenantId);
        resultList.add(map.get("id").toString());
        while (true) {
            SysDept sysDept = sysDeptDao.selectOne(new QueryWrapper<SysDept>().eq("id", map.get("parentId")));
            if (sysDept == null) {
                break;
            }
            map.put("parentId", sysDept.getPid());
            resultList.add(sysDept.getId().toString());
        }
        return resultList;
    }

    @Override
    public List<SysUserDetailVO> getUserDetailList(String id) {
        return sysUserDao.getUserDetailList(id);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public SysUser register(SysUserDTO dto) {
        if (!ObjectUtils.isEmpty(dto.getId())) {
            return dto;
        }
        SysUser user = sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getId, SysUser::getLoginName, SysUser::getMobile)
                .eq(SysUser::getMobile, dto.getMobile())
                .last(TableConstant.LIMIT_ONE));
        // 是否注册过？
        if (!ObjectUtils.isEmpty(user)) {
            // 登录名是否变更？
            if (!ObjectUtils.isEmpty(dto.getLoginName())
                    && !dto.getLoginName().equals(user.getLoginName())) {
                if (!ObjectUtils.isEmpty(sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>()
                        .select(SysUser::getId)
                        .eq(SysUser::getLoginName, dto.getLoginName())
                        .last(TableConstant.LIMIT_ONE)))) {
                    throw new ResultException("登录名已经存在，请更换");
                }
                // 修改登录名
                SysUser updateLoginName = new SysUser();
                updateLoginName.setId(user.getId());
                updateLoginName.setLoginName(dto.getLoginName());
                if (sysUserDao.updateById(updateLoginName) != 1) {
                    throw new TransactionalException();
                }
            }
            return user;
        }
        // 新用户 START
        if (ObjectUtils.isEmpty(dto.getLoginName())) {
            dto.setLoginName("YK" + dto.getMobile() + new Random().nextInt(10));
        } else {
            if (!ObjectUtils.isEmpty(sysUserDao.selectOne(new QueryWrapper<SysUser>()
                    .select(TableConstant.ID)
                    .eq("login_name", dto.getLoginName())
                    .last(TableConstant.LIMIT_ONE)))) {
                throw new ResultException("登录名已经存在，请更换");
            }
        }
        // 新用户
        user = new SysUser();
        BeanUtils.copyProperties(dto, user);
        Map<String, String> map = PasswordUtil.passwordMd5(AppConstant.DEFAULT_PASSWORD);
        user.setPassword(map.get("password"));
        user.setSalt(map.get("salt"));
        if (sysUserDao.insertSysUser(user) != 1) {
            throw new TransactionalException();
        }
        return user;
    }

    @Override
    public AppCenterVO appCenter(Long id) {
        return sysUserDao.appCenter(id);
    }

    @Override
    public Result<Object> changeMobile(SysUserDTO dto, SysUserVO currentUser) {
        // 校验手机号是否已经存在
        SysUser mobile = sysUserDao.selectOne(new QueryWrapper<SysUser>()
                .select(TableConstant.ID)
                .eq("mobile", dto.getMobile())
                .ne(TableConstant.ID, currentUser.getId())
                .last(TableConstant.LIMIT_ONE));
        if (!ObjectUtils.isEmpty(mobile)) {
            return Result.error("该手机号已经存在");
        }
        // 校验验证码
        redisUtils.checkCodeByMobile(dto.getMobile(), dto.getCode());
        // 修改手机号
        return this.update(new UpdateWrapper<SysUser>()
                .set("mobile", dto.getMobile())
                .eq(TableConstant.ID, currentUser.getId())) ? Result.ok() : Result.error();
    }

    @Override
    public Result<Object> pushCode(SysUserDTO dto) {
        // 发送验证码
        return Result.ok(redisUtils.pushCodeByMobile(dto.getMobile()));
    }

    @Override
    public Result<Object> changePasswordByCode(SysUserDTO dto) {
        redisUtils.checkCodeByMobile(dto.getMobile(), dto.getCode());
        SysUser entity = sysUserDao.selectOne(new QueryWrapper<SysUser>()
                .select(TableConstant.ID)
                .eq("mobile", dto.getMobile())
                .last(TableConstant.LIMIT_ONE));
        Map<String, String> map = PasswordUtil.passwordMd5(dto.getPassword());
        entity.setPassword(map.get("password"));
        entity.setSalt(map.get("salt"));
        return this.updateById(entity) ? Result.ok() : Result.error();
    }

    @Override
    public SysUserPerfect pcBaseEcho(SysUserDTO dto, SysUserVO currentUser) {
        return sysUserDao.getBaseAndProfile(dto.getMobile(), currentUser.getTenant().getId());
    }

    @Override
    public SysUser mAppCenter(SysUserVO currentUser) {
        SysUserPerfect baseAndProfile = sysUserDao.getBaseAndProfile(currentUser.getId(), currentUser.getTenant().getId());
        SysUser sysUser = new SysUser();
        sysUser.setNickName(baseAndProfile.getNickName());
        sysUser.setMobile(baseAndProfile.getMobile().replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
        sysUser.setHeadImg(baseAndProfile.getHeadImg());
        return sysUser;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateOneWithMobile(String n, String o) {
        SysUser user = sysUserDao.selectOne(new QueryWrapper<SysUser>()
                .select(TableConstant.ID)
                .eq("mobile", n)
                .last(TableConstant.LIMIT_ONE));
        if (!ObjectUtils.isEmpty(user)) {
            throw new TransactionalException(n + " 该手机号已经被注册");
        }
        // 修改手机号
        user = new SysUser();
        user.setMobile(n);
        if (sysUserDao.update(user, new UpdateWrapper<SysUser>()
                .eq("mobile", o)) != 1) {
            throw new TransactionalException();
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateOneWithLoginName(String n, String o) {
        SysUser user = sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getId)
                .eq(SysUser::getLoginName, n)
                .last(TableConstant.LIMIT_ONE));
        if (!ObjectUtils.isEmpty(user)) {
            throw new TransactionalException(n + " 该登录名已经被注册");
        }
        // 修改登录名
        user = new SysUser();
        user.setLoginName(n);
        if (sysUserDao.update(user, new LambdaUpdateWrapper<SysUser>()
                .eq(SysUser::getLoginName, o)) != 1) {
            throw new TransactionalException();
        }
    }

    @Override
    public Result<Object> checkLoginName(SysUserDTO dto, SysUserVO currentUser) {
        if (ObjectUtils.isEmpty(sysUserDao.selectOne(new LambdaQueryWrapper<SysUser>()
                .select(SysUser::getId)
                .eq(SysUser::getLoginName, dto.getLoginName())))) {
            throw new ResultException("手机号已存在");
        }
        return Result.ok();
    }

    @Override
    public SysUserVO pcEditEcho(Long userId) {
        return sysUserDao.pcEditEcho(userId);
    }

    @Override
    public Result<Object> pcClearPwdErr(Long userId) {
        String loginName = sysUserDao.getLoginNameByTenantUserId(userId);
        redisUtils.clearPwdErrCount(loginName, LoginType.SYS);
        return Result.ok();
    }

    public static void main(String[] args) {
        Map<String, String> map = PasswordUtil.passwordMd5(AppConstant.DEFAULT_PASSWORD);
        System.out.println(map);
    }

}